home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume3 / scpp / part2 < prev    next >
Encoding:
Internet Message Format  |  1986-11-30  |  39.0 KB

  1. From: genrad!masscomp!tektronix!tekig4!bradn
  2. Subject: scpp - a selective C preprocessor (Part 2 of 2)
  3. Newsgroups: mod.sources
  4. Approved: jpn@panda.UUCP
  5.  
  6. Mod.sources:  Volume 3, Issue 14
  7. Submitted by: decvax!tektronix!tekig4!bradn
  8.  
  9.  
  10. This is the second half of scpp.  The first half contains a brief explanation
  11. of the purpose of the program.
  12.  
  13. Brad Needham
  14. Tektronix, Inc.
  15. ...decvax!tektronix!tekig4!bradn
  16.  
  17. -------- cut along the dashed line -----
  18. #! /bin/sh
  19. # This is a shell archive, meaning:
  20. # 1. Remove everything above the #! /bin/sh line.
  21. # 2. Save the resulting text in a file.
  22. # 3. Execute the file with /bin/sh (not csh) to create the files:
  23. #    parse.y
  24. #    scpp.c
  25. #    scpp.h
  26. # This archive created: Thu Sep 19 12:35:40 1985
  27. export PATH; PATH=/bin:$PATH
  28. echo shar: extracting "'parse.y'" '(10067 characters)'
  29. if test -f 'parse.y'
  30. then
  31.     echo shar: will not over-write existing file "'parse.y'"
  32. else
  33. sed 's/^    X//' << \SHAR_EOF > 'parse.y'
  34.     X/*
  35.     X * parse.y - #if parser for the selective C preprocessor, scpp.
  36.     X *
  37.     X * Copyright (c) 1985 by
  38.     X * Tektronix, Incorporated Beaverton, Oregon 97077
  39.     X * All rights reserved.
  40.     X *
  41.     X * Permission is hereby granted for personal, non-commercial
  42.     X * reproduction and use of this program, provided that this
  43.     X * notice and all copyright notices are included in any copy.
  44.     X */
  45.     X
  46.     X%term    MUL        /* *        */
  47.     X%term    DIV        /* /        */
  48.     X%term    MOD        /* %        */
  49.     X%term    PLUS        /* +        */
  50.     X%term    MINUS        /* -        */
  51.     X%term    LS        /* <<        */
  52.     X%term    RS        /* >>        */
  53.     X%term    AND        /* &        */
  54.     X%term    OR        /* |        */
  55.     X%term    ER        /* ^        */
  56.     X%term    LT        /* <        */
  57.     X%term    LE        /* <=        */
  58.     X%term    GT        /* >        */
  59.     X%term    GE        /* >=        */
  60.     X%term    EQ        /* ==        */
  61.     X%term    NE        /* !=        */
  62.     X%term    ANDAND        /* &&        */
  63.     X%term    OROR        /* ||        */
  64.     X%term    CM        /* , (comma)    */
  65.     X%term    QUEST        /* ?        */
  66.     X%term    COLON        /* :        */
  67.     X%term    NOT        /* !        */
  68.     X%term    COMPL        /* ~        */
  69.     X%term    LP        /* (        */
  70.     X%term    RP        /* )        */
  71.     X%term    INT        /* an integer    */
  72.     X%term    FLOAT        /* a float    */
  73.     X%term    IDENT        /* a identifier    */
  74.     X%term    QUOTE        /* ' (apostrophe) */
  75.     X%term    DQUOTE        /* "        */
  76.     X%term    BACKS        /* \ (backslash) */
  77.     X%term    OPENC        /* open comment sequence */
  78.     X%term    CLOSEC        /* close comment sequence */
  79.     X%term    WHITE        /* whitespace    */
  80.     X%term    NL        /* newline    */
  81.     X%term    QNL        /* escaped (quoted) newline    */
  82.     X%term    COMMENT        /* a comment    */
  83.     X%term    OTHER        /* anything else */
  84.     X%term    STRING        /* a double-quote enclosed string constant    */
  85.     X%term    CHARS        /* a single-quote enclosed char constant    */
  86.     X%term    POUNDLINE    /*
  87.     X             * The initial '#' of a preprocessor directive
  88.     X             * (as opposed to a normal '#', which is of type OTHER).
  89.     X             */
  90.     X%term    DEFMAC        /* an uninterpreted 'defined(x)' invocation    */
  91.     X
  92.     X%left    CM
  93.     X%right    QUEST COLON
  94.     X%left    OROR
  95.     X%left    ANDAND
  96.     X%left    OR
  97.     X%left    ER
  98.     X%left    AND
  99.     X%left    EQ NE
  100.     X%left    LT LE GE GT
  101.     X%left    LS RS
  102.     X%left    PLUS MINUS
  103.     X%left    MUL DIV MOD
  104.     X%right    NOT COMPL
  105.     X%left    LP
  106.     X
  107.     X%union {
  108.     X    int intval;        /* yacc stack entries    */
  109.     X    struct anode *lexval;    /* everything in this file    */
  110.     X}
  111.     X
  112.     X%type <lexval>    exp e term
  113.     X%type <lexval> MUL DIV MOD PLUS MINUS LS RS AND OR ER LT LE GT GE EQ NE
  114.     X        ANDAND OROR CM QUEST COLON NOT COMPL LP RP INT FLOAT IDENT
  115.     X        QUOTE DQUOTE BACKS OPENC CLOSEC WHITE NL QNL COMMENT OTHER
  116.     X        STRING CHARS POUNDLINE DEFMAC
  117.     X
  118.     X%{
  119.     X# include "scpp.h"
  120.     X
  121.     X/*
  122.     X * struct anode - the structure used to pass strings.
  123.     X *  Allocated by mknode();
  124.     X *  Deallocated by freenode().
  125.     X * The string described will be in pend[] and is NOT NULL-TERMINATED.
  126.     X */
  127.     X
  128.     Xstruct anode {
  129.     X    int an_val;    /*
  130.     X             * lexical (token) value of this string.
  131.     X             * A value of 0 == this node is free.
  132.     X             */
  133.     X    int an_ifval;    /* integer result of this expression */
  134.     X};
  135.     X
  136.     X# define NODESIZ 100    /* max number of nodes in a #if expresssion    */
  137.     Xstruct anode nodepool[NODESIZ];
  138.     X
  139.     Xstruct anode *mknode();
  140.     X
  141.     X# define NIL ((struct anode *) 0)
  142.     X%}
  143.     X
  144.     X%start exp
  145.     X%%
  146.     Xexp:    e
  147.     X        {
  148.     X            /*
  149.     X             * If the expression can be evaluated, set the result
  150.     X             */
  151.     X
  152.     X            if ($1->an_val == INT) {
  153.     X                *curif |= $1->an_ifval != 0 ?
  154.     X                  IF_TRUE : IF_FALSE;
  155.     X            }
  156.     X            freenode($1);
  157.     X        }
  158.     X    ;
  159.     Xe:      e MUL e
  160.     X        {
  161.     X            $1->an_ifval = $1->an_ifval * $3->an_ifval;
  162.     X        binop:
  163.     X            $$ = $1;
  164.     X            if ($1->an_val == INT && $3->an_val == INT) {
  165.     X                $$->an_val == INT;
  166.     X            } else {
  167.     X                $$->an_val = OTHER;
  168.     X            }
  169.     X            freenode($2);
  170.     X            freenode($3);
  171.     X        }
  172.     X    | e DIV e
  173.     X        {
  174.     X          if ($3->an_ifval == 0 && $3->an_val == INT) {
  175.     X            $3->an_val = OTHER;
  176.     X            warnf("division by zero in #if");
  177.     X          } else {
  178.     X            $1->an_ifval = $1->an_ifval / $3->an_ifval;
  179.     X          }
  180.     X          goto binop;
  181.     X        }
  182.     X    | e MOD e
  183.     X        {
  184.     X          if ($3->an_ifval == 0 && $3->an_val == INT) {
  185.     X            $3->an_val = OTHER;
  186.     X            warnf("mod by zero in #if");
  187.     X          } else {
  188.     X            $1->an_ifval = $1->an_ifval % $3->an_ifval;
  189.     X          }
  190.     X          goto binop;
  191.     X        }
  192.     X    | e PLUS e
  193.     X        {$1->an_ifval = $1->an_ifval + $3->an_ifval; goto binop;}
  194.     X    | e MINUS e
  195.     X        {$1->an_ifval = $1->an_ifval - $3->an_ifval; goto binop;}
  196.     X    | e LS e
  197.     X        {$1->an_ifval = $1->an_ifval << $3->an_ifval; goto binop;}
  198.     X    | e RS e
  199.     X        {$1->an_ifval = $1->an_ifval >> $3->an_ifval; goto binop;}
  200.     X    | e LT e
  201.     X        {$1->an_ifval = $1->an_ifval < $3->an_ifval; goto binop;}
  202.     X    | e GT e
  203.     X        {$1->an_ifval = $1->an_ifval > $3->an_ifval; goto binop;}
  204.     X    | e LE e
  205.     X        {$1->an_ifval = $1->an_ifval <= $3->an_ifval; goto binop;}
  206.     X    | e GE e
  207.     X        {$1->an_ifval = $1->an_ifval >= $3->an_ifval; goto binop;}
  208.     X    | e EQ e
  209.     X        {$1->an_ifval = $1->an_ifval == $3->an_ifval; goto binop;}
  210.     X    | e NE e
  211.     X        {$1->an_ifval = $1->an_ifval != $3->an_ifval; goto binop;}
  212.     X    | e AND e
  213.     X        {$1->an_ifval = $1->an_ifval & $3->an_ifval; goto binop;}
  214.     X    | e ER e
  215.     X        {$1->an_ifval = $1->an_ifval ^ $3->an_ifval; goto binop;}
  216.     X    | e OR e
  217.     X        {$1->an_ifval = $1->an_ifval | $3->an_ifval; goto binop;}
  218.     X    | e ANDAND e
  219.     X        {
  220.     X            /*
  221.     X             * since this is a logical AND, its value
  222.     X             *  is known if either subexpression is false.
  223.     X             */
  224.     X
  225.     X            $$ = $1;
  226.     X            if ($1->an_val == INT && $3->an_val == INT) {
  227.     X                /* both subexpressions are known */
  228.     X                $$->an_ifval = $1->an_ifval && $3->an_ifval;
  229.     X            } else {
  230.     X                if (($1->an_val == INT && !$1->an_ifval) ||
  231.     X                    ($3->an_val == INT && !$3->an_ifval)) {
  232.     X                    $$->an_val = INT;
  233.     X                    $$->an_ifval = FALSE;
  234.     X                } else {
  235.     X                    $$->an_val = OTHER;
  236.     X                }
  237.     X            }
  238.     X            freenode($2); freenode($3);
  239.     X        }
  240.     X    | e OROR e
  241.     X        {
  242.     X            /*
  243.     X             * since this is a logical OR, its value
  244.     X             *  is known if either subexpression is true.
  245.     X             */
  246.     X
  247.     X            $$ = $1;
  248.     X            if ($1->an_val == INT && $3->an_val == INT) {
  249.     X                /* both subexpressions are known */
  250.     X                $$->an_ifval = $1->an_ifval || $3->an_ifval;
  251.     X            } else {
  252.     X                if (($1->an_val == INT && $1->an_ifval) ||
  253.     X                    ($3->an_val == INT && $3->an_ifval)) {
  254.     X                    $$->an_val = INT;
  255.     X                    $$->an_ifval = TRUE;
  256.     X                } else {
  257.     X                    $$->an_val = OTHER;
  258.     X                }
  259.     X            }
  260.     X            freenode($2); freenode($3);
  261.     X        }
  262.     X    | e QUEST e COLON e
  263.     X        {
  264.     X            /*
  265.     X             * since this is an IF-ELSE, its value is known
  266.     X             * in some cases even if one subexpression is unknown.
  267.     X             */
  268.     X
  269.     X            $$ = $1;
  270.     X            if ($1->an_val == INT) {
  271.     X                if ($1->an_ifval) {
  272.     X                    $$->an_val = $3->an_val;
  273.     X                    $$->an_ifval = $3->an_ifval;
  274.     X                } else {
  275.     X                    $$->an_val = $5->an_val;
  276.     X                    $$->an_ifval = $5->an_ifval;
  277.     X                }
  278.     X            } else {
  279.     X                $$->an_val = OTHER;
  280.     X            }
  281.     X            freenode($2); freenode($3); freenode($4);
  282.     X            freenode($5);
  283.     X        }
  284.     X    | e CM e
  285.     X        {
  286.     X            /*
  287.     X             * since this is a comma operator, the value of
  288.     X             * the first expression is irrelevant.
  289.     X             */
  290.     X
  291.     X            $$ = $3;
  292.     X            freenode($1);
  293.     X            freenode($2);
  294.     X        }
  295.     X    | term
  296.     X        {$$ = $1;}
  297.     X    ;
  298.     Xterm:
  299.     X      MINUS term
  300.     X        {
  301.     X            $2->an_ifval = -($2->an_ifval);
  302.     X        unop:
  303.     X            $$ = $2;
  304.     X            freenode($1);
  305.     X        }
  306.     X    | NOT term
  307.     X        {$2->an_ifval = !($2->an_ifval); goto unop;}
  308.     X    | COMPL term
  309.     X        {$2->an_ifval = ~($2->an_ifval); goto unop;}
  310.     X    | LP e RP
  311.     X        {
  312.     X            $$ = $2;
  313.     X            freenode($1); freenode($3);
  314.     X        }
  315.     X    | INT
  316.     X        {$$= $1;}
  317.     X    | IDENT
  318.     X        {/* an uninterpreted macro */ $$ = $1;}
  319.     X    | DEFMAC
  320.     X        {/* an uninterpreted 'defined(x)' invocation */ $$ = $1;}
  321.     X    ;
  322.     X%%
  323.     X
  324.     Xyyerror(s)
  325.     Xchar *s;
  326.     X{
  327.     X    struct anode *anp;
  328.     X
  329.     X    /* free all nodes */
  330.     X
  331.     X    for (anp = &nodepool[0]; anp < &nodepool[NODESIZ]; anp++) {
  332.     X        anp->an_val = 0;
  333.     X    }
  334.     X    warnf("syntax error in #if");
  335.     X}
  336.     X
  337.     X/*
  338.     X * yylex() - the lexical analyzer for #if statements.
  339.     X *  yylex() reads from the stream of interpreted macros, skipping
  340.     X *  insignificant tokens, then sets yylval appropriately and returns
  341.     X *  the token number of the token.
  342.     X */
  343.     X
  344.     Xint
  345.     Xyylex()
  346.     X{
  347.     X    int tok;
  348.     X
  349.     X
  350.     X    /*
  351.     X     * Skip whitespace, quoted newlines, and interpreted preprocessor
  352.     X     * directives;
  353.     X     * End-of-file or an unquoted newline marks the end of the parse;
  354.     X     * calculate the value of integers and character constants.
  355.     X     */
  356.     X
  357.     X    if (!(yylval.lexval = mknode())) {
  358.     X        return(0);
  359.     X    }
  360.     X
  361.     X    while ((tok = gintok()) == WHITE || tok == COMMENT || tok == QNL)
  362.     X        ;
  363.     X
  364.     X    if (tok == 0 || tok == NL) {
  365.     X        freenode(yylval.lexval);
  366.     X        yylval.lexval = NIL;
  367.     X        return(0);
  368.     X    }
  369.     X
  370.     X    yylval.lexval->an_val = tok;
  371.     X    if (tok == INT) {
  372.     X        yylval.lexval->an_ifval = inttok(curtext, nxtout);
  373.     X    } else if (tok == CHARS) {
  374.     X        yylval.lexval->an_val = INT;
  375.     X        yylval.lexval->an_ifval = chartok(curtext, nxtout);
  376.     X    }
  377.     X    return(yylval.lexval->an_val);
  378.     X}
  379.     X
  380.     X/*
  381.     X * inttok - convert integer token.
  382.     X *  Given the bounds of a token of type INT, return the value of that integer.
  383.     X */
  384.     X
  385.     Xint
  386.     Xinttok(s, e)
  387.     Xchar *s, *e;
  388.     X{
  389.     X    char *str;    /* points to a (dynamically alloc'ed) copy of the tok */
  390.     X    char *cp;
  391.     X    int base;    /* the radix of this integer            */
  392.     X    int value;    /* the value to return                */
  393.     X    int digit;    /* the value of the current digit        */
  394.     X
  395.     X    /*
  396.     X     * get a copy of the token (to remove ATTN bytes and null-terminate
  397.     X     *  the string), and find out what the number base is.
  398.     X     */
  399.     X
  400.     X    str = savtok(s, e);
  401.     X    cp = str;
  402.     X    if (*cp != '0') {
  403.     X        base = 10;
  404.     X    } else {
  405.     X        if (*cp && (*++cp == 'x' || *cp == 'X')) {
  406.     X            ++cp;
  407.     X            base = 16;
  408.     X        } else {
  409.     X            base = 8;
  410.     X        }
  411.     X    }
  412.     X
  413.     X    /*
  414.     X     * convert the string
  415.     X     */
  416.     X
  417.     X    value = 0;
  418.     X    for (;*cp; ++cp) {
  419.     X        if (*cp >= '0' && *cp <= '7') {
  420.     X            digit = (int)(*cp - '0');
  421.     X        } else if (*cp >= '8' && *cp <= '9' && base >= 10) {
  422.     X            digit = (int)(*cp - '0');
  423.     X        } else if (*cp >= 'a' && *cp <= 'f' && base == 16) {
  424.     X            digit = (int)(*cp - 'a') + 10;
  425.     X        } else if (*cp >= 'A' && *cp <= 'F' && base == 16) {
  426.     X            digit = (int)(*cp - 'A') + 10;
  427.     X        } else {
  428.     X            break;
  429.     X        }
  430.     X        value = value * base + digit;
  431.     X    }
  432.     X
  433.     X    free(str);
  434.     X    return(value);
  435.     X}
  436.     X
  437.     X/*
  438.     X * chartok() - convert a character constant token.
  439.     X *  given the bounds of a character constant, return the integer value
  440.     X *   of that character constant.
  441.     X */
  442.     X 
  443.     Xint
  444.     Xchartok(s, e)
  445.     Xchar *s, *e;
  446.     X{
  447.     X    char *str;    /* (dynamically alloc'ed) copy of the token    */
  448.     X    char *cp;
  449.     X    int value;    /* value to return                */
  450.     X    int cnt;
  451.     X
  452.     X
  453.     X    str = savtok(s, e);
  454.     X
  455.     X    cp = str + 1;
  456.     X    if (*cp != '\\') {
  457.     X        value = (int) *cp;
  458.     X    } else if (*++cp == 'n') {
  459.     X        value = (int) '\n';
  460.     X    } else if (*cp == 't') {
  461.     X        value = (int) '\t';
  462.     X    } else if (*cp == 'b') {
  463.     X        value = (int) '\b';
  464.     X/*--read the book to find out the other chars supported--*/
  465.     X    } else if (*cp >= '0' && *cp <= '7') {
  466.     X        for (value = 0, cnt = 3; cnt >= 1 && *cp >= '0' && *cp <= '7';
  467.     X          --cnt, ++cp) {
  468.     X            value = value * 8 + (int)(*cp - '0');
  469.     X        }
  470.     X    } else {
  471.     X        value = (int) *cp;
  472.     X    }
  473.     X
  474.     X    free(str);
  475.     X    return(value);
  476.     X}
  477.     X
  478.     Xstruct anode *
  479.     Xmknode()
  480.     X{
  481.     X    struct anode *anp;
  482.     X
  483.     X    for (anp = &nodepool[0];
  484.     X      anp < &nodepool[NODESIZ] && anp->an_val != 0; anp++)
  485.     X        ;
  486.     X    if (anp >= &nodepool[NODESIZ]) {
  487.     X        warnf("#if expression too complex");
  488.     X        return(NIL);
  489.     X    }
  490.     X    anp->an_val = OTHER;
  491.     X    return(anp);
  492.     X}
  493.     X
  494.     Xfreenode(n)
  495.     Xstruct anode *n;
  496.     X{
  497.     X    n->an_val = 0;
  498.     X}
  499. SHAR_EOF
  500. if test 10067 -ne "`wc -c < 'parse.y'`"
  501. then
  502.     echo shar: error transmitting "'parse.y'" '(should have been 10067 characters)'
  503. fi
  504. fi # end of overwriting check
  505. echo shar: extracting "'scpp.c'" '(14405 characters)'
  506. if test -f 'scpp.c'
  507. then
  508.     echo shar: will not over-write existing file "'scpp.c'"
  509. else
  510. sed 's/^    X//' << \SHAR_EOF > 'scpp.c'
  511.     X/*
  512.     X * scpp.c - main processing for the selective C preprocessor, scpp.
  513.     X *
  514.     X * Copyright (c) 1985 by
  515.     X * Tektronix, Incorporated Beaverton, Oregon 97077
  516.     X * All rights reserved.
  517.     X *
  518.     X * Permission is hereby granted for personal, non-commercial
  519.     X * reproduction and use of this program, provided that this
  520.     X * notice and all copyright notices are included in any copy.
  521.     X */
  522.     X
  523.     X#define VARS
  524.     X# include <stdio.h>
  525.     X# include "scpp.h"
  526.     X# include "y.tab.h"
  527.     X
  528.     X/*
  529.     X * actual[] - the array of actual parameters of the macro currently being
  530.     X *  interpreted.
  531.     X */
  532.     X
  533.     Xstruct anactual {
  534.     X    char *aa_val;    /*
  535.     X             * the value of this actual (a pointer to the null-
  536.     X             * terminator.  see amacro.am_val in scpp.h).
  537.     X             */
  538.     X    char *aa_mem;    /*
  539.     X             * points to the beginning of the aa_val string.
  540.     X             * Used to later free the value's memory.
  541.     X             */
  542.     X};
  543.     X#define ACTSIZ MAXPARMS
  544.     Xstruct anactual actual[ACTSIZ];
  545.     Xstruct anactual *actp;    /* the next available slot in actual[] */
  546.     X
  547.     X
  548.     X
  549.     Xmain(argc, argv)
  550.     Xint argc;
  551.     Xchar **argv;
  552.     X{
  553.     X    int tok;    /* current token's value    */
  554.     X    char *cp;
  555.     X    char *ep;
  556.     X    char **dp;    /* where within dirlist to put the next directory */
  557.     X    struct amacro *np;
  558.     X    char *name;    /* name of the current macro    */
  559.     X    char *val;    /* value of the current macro    */
  560.     X    char *defmagic = "defined";    /* name of the 'defined()' macro */
  561.     X    struct amacro *magmac;    /* (temp) slot for the magic macro */
  562.     X
  563.     X    /*
  564.     X     * init all the global structures
  565.     X     */
  566.     X
  567.     X    nxtout = &pend[0];
  568.     X    curfile = &filestk[-1];
  569.     X    nxtin = &istk[ISTKSIZ];
  570.     X    curif = &ifstk[-1];
  571.     X    
  572.     X    nxtfile = &catlist[0];
  573.     X    dp = &dirlist[0];
  574.     X
  575.     X    /*
  576.     X     * setup the keyword symbols and the special macro, 'defined()'.
  577.     X     */
  578.     X
  579.     X    ikeywords();
  580.     X    magmac = findmac(defmagic, defmagic + strlen(defmagic));
  581.     X    if (magmac->am_name) {
  582.     X        bomb("INTERNAL: 'defined()' macro slot in use");
  583.     X    }
  584.     X    magmac->am_name = defmagic;
  585.     X    magmac->am_npar = 1;
  586.     X    magmac->am_val = &magicval;
  587.     X
  588.     X    while (++argv, --argc > 0) {
  589.     X        cp = *argv;
  590.     X        if (*cp == '-' && *(cp + 1) != '\0') {
  591.     X            switch(*++cp) {
  592.     X            case 'C':
  593.     X                savcom = TRUE;
  594.     X                break;
  595.     X            case 'I':
  596.     X                *dp++ = cp + 1;
  597.     X                break;
  598.     X            case 'M':
  599.     X                /*
  600.     X                 * for each name in the list of whitespace-
  601.     X                 *  separated macro names,
  602.     X                 * Setup a slot for that macro, but leave it
  603.     X                 *  undefined.
  604.     X                 */
  605.     X
  606.     X                while (*cp) {
  607.     X                    while (*++cp == ' ' || *cp == '\t' ||
  608.     X                        *cp == '\n')
  609.     X                        ;
  610.     X                    if (*cp == '\0') {
  611.     X                        break;
  612.     X                    }
  613.     X                    for (name = cp; *cp != '\0' &&
  614.     X                      *cp != ' ' && *cp != '\t' &&
  615.     X                      *cp != '\n'; ++cp)
  616.     X                        ;
  617.     X
  618.     X                    np = findmac(name, cp);
  619.     X                    if (np->am_name == (char *) 0) {
  620.     X                        np->am_name = savtok(name, cp);
  621.     X                        np->am_npar = -1;
  622.     X                    }
  623.     X                    /* am_val is left as zero */
  624.     X                }
  625.     X                break;
  626.     X            case 'D':
  627.     X                for (name = ++cp; *cp != '\0' && *cp != '=';
  628.     X                  ++cp)
  629.     X                    ;
  630.     X                if (name == cp) {
  631.     X                    warn("missing macro name in `%s'",
  632.     X                      name - 2);
  633.     X                    break;
  634.     X                }
  635.     X
  636.     X                if (*cp == '\0') {
  637.     X                    /*
  638.     X                     * macro name with no definition.
  639.     X                     * Define the name with no parameters
  640.     X                     *  and with a value of "1".
  641.     X                     */
  642.     X
  643.     X                    defmac(name, cp, -1, "1");
  644.     X                } else {
  645.     X                    /* macro + definition */
  646.     X
  647.     X                    for (*cp++ = '\0', val = cp;
  648.     X                      *cp != '\0'; ++cp)
  649.     X                        ;
  650.     X                    defmac(name, name + strlen(name),
  651.     X                      -1, val);
  652.     X                }
  653.     X                break;
  654.     X            default:
  655.     X                bomb("unknown switch `%c'", *cp);
  656.     X            }
  657.     X        } else {
  658.     X            *nxtfile++ = cp;
  659.     X        }
  660.     X    }
  661.     X
  662.     X    if (nxtfile == &catlist[0]) {
  663.     X        *nxtfile++ = "-";
  664.     X    }
  665.     X    *nxtfile = (char *) 0;
  666.     X    nxtfile = &catlist[0];
  667.     X
  668.     X    *dp++ = "/usr/include";
  669.     X    *dp = (char *) 0;
  670.     X
  671.     X    /*
  672.     X     * prime the input stack and go,
  673.     X     * interpreting preprocessor directives along the way.
  674.     X     */
  675.     X
  676.     X    pushfile(*nxtfile++, PF_NOLOOK, PF_NOHIDE);
  677.     X    do {
  678.     X        tok = gintok();
  679.     X        if (tok == POUNDLINE) {
  680.     X            tok = doctrl(curtext);
  681.     X        }
  682.     X        outpend();    /* even the 0 token needs to be flushed.
  683.     X                 * Otherwise, incomplete comments at the end
  684.     X                 * of the file would be destroyed.
  685.     X                 */
  686.     X    } while (tok != 0);
  687.     X    writepend();        /* flush trailing output    */
  688.     X
  689.     X    if (curif >= &ifstk[0]) {
  690.     X        warnf("missing endif");
  691.     X    }
  692.     X
  693.     X    exit(sawerror ? 1 : 0);
  694.     X}
  695.     X
  696.     Xint
  697.     Xgintok()    /* get a token, interpreting macro's    */
  698.     X{
  699.     X    int tok;        /* the current token's value    */
  700.     X    struct amacro *mac;    /* the current macro        */
  701.     X    struct amacro *defsym;    /* the macro being checked for 'defined()' */
  702.     X    char *mactext;        /*
  703.     X                 * the start of the invocation of a macro
  704.     X                 * which has parameters.
  705.     X                 */
  706.     X    char *start;        /* the start of the current parameter    */
  707.     X    int nest;        /*
  708.     X                 * current nesting level of parentheses.
  709.     X                 * used to avoid misinterpreting commas within
  710.     X                 * nested parens as parameter separators.
  711.     X                 */
  712.     X    char *defident;        /*
  713.     X                 * The IDENT parameter for the magic macro,
  714.     X                 * 'defined()' (dynamically alloc'ed).
  715.     X                 * If gintok() is interpreting the magic macro,
  716.     X                 * this variable is marked so that, during the
  717.     X                 * parameter parsing, the first IDENT is saved
  718.     X                 * here.
  719.     X                 */
  720.     X    int parmgripe;        /*
  721.     X                 * "an error message about parameters of
  722.     X                 * this macro has already been printed."
  723.     X                 */
  724.     X    int i;            /* an actual-parameter index    */
  725.     X    char *cp;        /* a temp pointer        */
  726.     X
  727.     X    /*
  728.     X     * special macro values (see scpp.h: struct amacro, field am_val):
  729.     X     *  noval == a null macro value;
  730.     X     *  oneval == a macro value of '1';
  731.     X     *  zeroval == a macro value of '0';
  732.     X     */
  733.     X
  734.     X    static char nv[2] = {'\0', '\0'};
  735.     X    static char *noval = &nv[1];
  736.     X    static char ov[3] = {'\0', '1', '\0'};
  737.     X    static char *oneval = &ov[2];
  738.     X    static char zv[3] = {'\0', '0', '\0'};
  739.     X    static char *zeroval = &zv[2];
  740.     X
  741.     X
  742.     X    tok = OTHER;
  743.     X    while (tok != DEFMAC && (tok = gtok()) != 0) {
  744.     X        if (tok == QUOTE || tok == DQUOTE) {
  745.     X            tok = gstrtok(tok);
  746.     X        }
  747.     X        if (tok != IDENT) {
  748.     X            return(tok);
  749.     X        }
  750.     X
  751.     X        if ((mac = findmac(curtext, nxtout))->am_name == (char *) 0 ||
  752.     X            mac->am_val == (char *) 0) {
  753.     X            /* there is no macro by this name currently defined */
  754.     X
  755.     X            return(tok);
  756.     X        }
  757.     X
  758.     X        /*
  759.     X         * tally this interpretation
  760.     X         */
  761.     X
  762.     X        ++ninterp;
  763.     X
  764.     X        if (mac->am_npar < 0) {
  765.     X            /*
  766.     X             * the macro has no formal parameters.
  767.     X             * pushback the replacement text and continue.
  768.     X             */
  769.     X
  770.     X            (void) dispose(curtext);
  771.     X            (void) pushmac(mac->am_val);
  772.     X            continue;
  773.     X        }
  774.     X
  775.     X        /* this is a macro with formals */
  776.     X
  777.     X        /*
  778.     X         * save the starting-point of the macro's text.
  779.     X         * Used for later disposal.  The text is not disposed
  780.     X         * here in case the macro is a 'defined()' of some non--M'ed
  781.     X         * macro.
  782.     X         */
  783.     X
  784.     X        mactext = curtext;
  785.     X
  786.     X        /*
  787.     X         * collect the comma-separated actual parameters of the macro,
  788.     X         * ignoring commas within pairs of parens or within strings.
  789.     X         */
  790.     X
  791.     X        parmgripe = FALSE;
  792.     X        actp = &actual[0];
  793.     X        nest = 0;
  794.     X        if (mac->am_val == &magicval) {
  795.     X            defident = &magicval;
  796.     X        } else {
  797.     X            defident = (char *) 0;
  798.     X        }
  799.     X
  800.     X        if ((tok = nonwhite(gtok)) != LP) {
  801.     X            warnf("missing parenthesis in macro");
  802.     X            parmgripe = TRUE;
  803.     X    
  804.     X            /* pushback the erroneous token    */
  805.     X            untok();
  806.     X        } else {
  807.     X            do {
  808.     X                /* collect one parameter */
  809.     X
  810.     X                start = nxtout;
  811.     X                while ((tok = gtok())) {
  812.     X                    if (tok == CM && nest == 0) {
  813.     X                        break;
  814.     X                    } else if (tok == RP) {
  815.     X                        if (nest > 0) {
  816.     X                            --nest;
  817.     X                        } else if (nest == 0) {
  818.     X                            break;
  819.     X                        }
  820.     X                    } else if (tok == LP) {
  821.     X                        ++nest;
  822.     X                    } else if (tok == QUOTE ||
  823.     X                      tok == DQUOTE) {
  824.     X                        tok = gstrtok(tok);
  825.     X                    } else if (tok == IDENT &&
  826.     X                      defident == &magicval) {
  827.     X                        defident =
  828.     X                          savtok(curtext, nxtout);
  829.     X                    }
  830.     X                }
  831.     X
  832.     X                /*
  833.     X                 * Warn about too many parameters, otherwise,
  834.     X                 * store the parameter in the format of
  835.     X                 * a macro value.
  836.     X                 */
  837.     X
  838.     X                if ((actp - &actual[0]) >= mac->am_npar) {
  839.     X                    if (!parmgripe) {
  840.     X                      warnf("macro parameter mismatch");
  841.     X                      parmgripe = TRUE;
  842.     X                    }
  843.     X                } else {
  844.     X                    cp = savtok(start - 1, curtext);
  845.     X                    *cp = '\0';
  846.     X                    actp->aa_mem = cp;
  847.     X                    while (*++cp)
  848.     X                        ;
  849.     X                    actp->aa_val = cp;
  850.     X                    ++actp;
  851.     X                }
  852.     X            } while (tok == CM);
  853.     X            if (tok != RP) {
  854.     X                if (!parmgripe) {
  855.     X                  warnf("missing parenthesis in macro");
  856.     X                  parmgripe = TRUE;
  857.     X                }
  858.     X            }
  859.     X        }
  860.     X
  861.     X        /*
  862.     X         * If there are too few actual parameters, fill out the
  863.     X         * list with null values.
  864.     X         */
  865.     X
  866.     X        while (actp - &actual[0] < mac->am_npar) {
  867.     X            if (!parmgripe) {
  868.     X                warnf("parameter mismatch");
  869.     X                parmgripe = TRUE;
  870.     X            }
  871.     X            actp->aa_val = noval;
  872.     X            actp->aa_mem = (char *) 0;
  873.     X            ++actp;
  874.     X        }
  875.     X
  876.     X        /*
  877.     X         * replace the macro invocation with the value of the macro,
  878.     X         *  replacing formal arguments with the corresponding actual.
  879.     X         */
  880.     X
  881.     X        if ((cp = mac->am_val) == &magicval) {
  882.     X            /*
  883.     X             * This is the magic macro, "defined(x)".
  884.     X             * Interpret only if the parameter is a -M'ed
  885.     X             *  macro and we are currently parsing a
  886.     X             *  #if expression.
  887.     X             * Lookup the parameter (if any);
  888.     X             * If the parameter is -M'ed, pushback a '1' or '0',
  889.     X             * depending on whether the macro is defined.
  890.     X             */
  891.     X
  892.     X            defsym = findmac(defident, defident + strlen(defident));
  893.     X            if (!defsym->am_name || !expparse) {
  894.     X                /*
  895.     X                 * Leave the invocation of defined() untouched.
  896.     X                 */
  897.     X
  898.     X                curtext = mactext;
  899.     X                tok = DEFMAC;
  900.     X            } else {
  901.     X                (void) dispose(mactext);
  902.     X                if (defsym->am_val) {
  903.     X                    (void) pushmac(oneval);
  904.     X                } else {
  905.     X                    (void) pushmac(zeroval);
  906.     X                }
  907.     X            }
  908.     X            free(defident);
  909.     X        } else {
  910.     X            (void) dispose(mactext);
  911.     X            while (*(cp = pushmac(cp)) == ATTN) {
  912.     X                i = (int) (*--cp) - 1;
  913.     X                if (i < 0 || i >= mac->am_npar) {
  914.     X                    warnf(
  915.     X"INTERNAL: parameter number %d out of bounds", i);
  916.     X                } else {
  917.     X                    (void) pushmac(actual[i].aa_val);
  918.     X                }
  919.     X            }
  920.     X        }
  921.     X
  922.     X        /*
  923.     X         * free the actual parameters.
  924.     X         */
  925.     X
  926.     X        while (--actp >= &actual[0]) {
  927.     X            if (actp->aa_mem) {
  928.     X                free(actp->aa_mem);
  929.     X            }
  930.     X        }
  931.     X    }
  932.     X    return(tok);
  933.     X}
  934.     X
  935.     X/*
  936.     X * gtok() - get a token without interpreting macros or preprocessor directives.
  937.     X *  This is the low-level lexical analyzer.  It exists only because Lex's
  938.     X *  analyzer chokes on long comments.
  939.     X */
  940.     X
  941.     Xint
  942.     Xgtok()
  943.     X{
  944.     X    int tok;
  945.     X
  946.     X
  947.     X    curtext = nxtout;
  948.     X    tok = xxlex();
  949.     X    if (tok == OPENC) {
  950.     X        while ((tok = xxlex()) != CLOSEC) {
  951.     X            if (tok == 0) {
  952.     X                warnf("unterminated comment");
  953.     X                return(0);
  954.     X            }
  955.     X        }
  956.     X        tok = COMMENT;
  957.     X    }
  958.     X    return(tok);
  959.     X}
  960.     X
  961.     X/*
  962.     X * gstrtok - get a string token.  Given the token which starts a string
  963.     X *  or character constant (I.E. QUOTE or DQUOTE), collect the string token
  964.     X *  as if it had been recognised by the lexical analyzer as a single token.
  965.     X */
  966.     X
  967.     Xint
  968.     Xgstrtok(tok)
  969.     Xint tok;        /* token which started the quoted string    */
  970.     X{
  971.     X    int tok2;        /* the next token's value    */
  972.     X    char *qstrt;        /* start of a string in pend[]    */
  973.     X
  974.     X    /*
  975.     X     * collect the string without interpreting
  976.     X     * macros.  Allow \' and \" within strings.
  977.     X     * Newline or EOF terminate strings.
  978.     X     * Save and restore curtext so that on returning,
  979.     X     * curtext points to the beginning of the token.
  980.     X     */
  981.     X
  982.     X    qstrt = curtext;
  983.     X    while ((tok2 = gtok()) != tok) {
  984.     X        if (tok2 == 0) {
  985.     X            /* unterminated quote    */
  986.     X            curtext = qstrt;
  987.     X            return(0);
  988.     X        }
  989.     X        if (tok2 == NL) {
  990.     X            /* unterminated quote. pushback the newline    */
  991.     X
  992.     X            untok();
  993.     X            break;
  994.     X        }
  995.     X        if (tok2 == BACKS) {
  996.     X            if (gtok() == 0) {
  997.     X                /* unterminated quote */
  998.     X                curtext = qstrt;
  999.     X                return(0);
  1000.     X            }
  1001.     X        }
  1002.     X    }
  1003.     X    curtext = qstrt;
  1004.     X    return(tok == DQUOTE ? STRING : CHARS);
  1005.     X}
  1006.     X
  1007.     X/*
  1008.     X * findmac - find a macro
  1009.     X *  given the bounds of what might be a macro name (possibly containing ATTN
  1010.     X *   bytes), return a pointer to the symbol table slot
  1011.     X *  corresponding to that name.
  1012.     X */
  1013.     X
  1014.     Xstruct amacro *
  1015.     Xfindmac(name, last)
  1016.     Xchar *name;    /* points to the beginning of the name.            */
  1017.     Xchar *last;    /* points to the char beyond the end of the name    */
  1018.     X{
  1019.     X    /*
  1020.     X     * hash the first 8 chars of the name (less ATTN bytes) into an index;
  1021.     X     * Use that index as a starting point for a linear search
  1022.     X     *  for either the matching slot or an empty slot.
  1023.     X     */
  1024.     X
  1025.     X    int idx;
  1026.     X    char *cp;
  1027.     X    char *tp;
  1028.     X    int cnt;
  1029.     X    struct amacro *np, *start;
  1030.     X
  1031.     X
  1032.     X    for (idx = 0, cp = name, cnt = 0; cp < last && cnt < 8; ++cp) {
  1033.     X        if (*cp == ATTN) {
  1034.     X            ++cp;
  1035.     X        } else {
  1036.     X            idx += (int) *cp++ & 0xff;
  1037.     X            ++cnt;
  1038.     X        }
  1039.     X    }
  1040.     X    start = np = &sym[idx % SYMSIZ];
  1041.     X
  1042.     X    while (np->am_name) {
  1043.     X        /*
  1044.     X         * compare the token at 'name' with the macro's name,
  1045.     X         * skipping ATTN bytes and their associated codes.
  1046.     X         */
  1047.     X
  1048.     X        for (tp = name, cp = np->am_name; tp < last; ++tp) {
  1049.     X            if (*tp == ATTN) {
  1050.     X                ++tp;
  1051.     X                continue;
  1052.     X            }
  1053.     X            if (*tp != *cp++) {
  1054.     X                break;
  1055.     X            }
  1056.     X        }
  1057.     X        if (tp == last) {
  1058.     X            /* the names match */
  1059.     X            break;
  1060.     X        }
  1061.     X
  1062.     X        if (++np >= &sym[SYMSIZ]) {
  1063.     X            np = &sym[0];
  1064.     X        }
  1065.     X        if (np == start) {
  1066.     X            bombf("symbol table overflow");
  1067.     X        }
  1068.     X    }
  1069.     X    return(np);
  1070.     X}
  1071.     X
  1072.     X/*
  1073.     X * defmac - define a macro
  1074.     X */
  1075.     X
  1076.     Xdefmac(name, end, npar, val)
  1077.     Xchar *name;        /* the start of the macro's name        */
  1078.     Xchar *end;        /* points to one char beyond the end of the name */
  1079.     Xint npar;        /* # of parameters (-1 == none)            */
  1080.     Xchar *val;        /* the beginning of the value string        */
  1081.     X{
  1082.     X    char *cp;
  1083.     X    struct amacro *np;
  1084.     X    struct akeyword *kp;
  1085.     X    char *malloc();
  1086.     X
  1087.     X
  1088.     X    /*
  1089.     X     * find the slot for the macro and give it a name if this is the
  1090.     X     * first occurrence of this name.
  1091.     X     */
  1092.     X
  1093.     X    np = findmac(name, end);
  1094.     X    if (!np->am_name) {
  1095.     X        np->am_name = savtok(name, end);
  1096.     X    } else {
  1097.     X        /*
  1098.     X         * Don't allow preprocessor keywords to be defined.
  1099.     X         */
  1100.     X
  1101.     X        if ((kp = findkey(np)) != (struct akeyword *) 0) {
  1102.     X            warnf("redeclaration of keyword \"%s\"", kp->ak_name);
  1103.     X            return;
  1104.     X        }
  1105.     X
  1106.     X        /*
  1107.     X         * if the macro is currently defined (I.E. has a value),
  1108.     X         *  reject redefinitions of magic macros.
  1109.     X         * compare the new and old values.
  1110.     X         * If the value or number of parameters differs,
  1111.     X         *  print a warning and destroy the old value.
  1112.     X         * If they are the same, do nothing (return).
  1113.     X         */
  1114.     X
  1115.     X        if (np->am_val) {
  1116.     X            if (np->am_val == &magicval) {
  1117.     X                warnf("cannot redefine implicit macro");
  1118.     X                return;
  1119.     X            }
  1120.     X            cp = np->am_val;
  1121.     X            while (*--cp)
  1122.     X                ;
  1123.     X            if (np->am_npar == npar && strcmp(cp + 1, val) == 0) {
  1124.     X                return;
  1125.     X            }
  1126.     X
  1127.     X            warnf("redeclaration of \"%s\"", np->am_name);
  1128.     X            free(cp);
  1129.     X        }
  1130.     X    }
  1131.     X
  1132.     X    /*
  1133.     X     * Set the new value and number of parameters.
  1134.     X     * Put a null introduction on the value;
  1135.     X     * Remember that am_val points to the *end* of the value.
  1136.     X     */
  1137.     X
  1138.     X    np->am_npar = npar;
  1139.     X
  1140.     X    if (!(cp = malloc((unsigned) strlen(val) + 2))) {
  1141.     X        bombf("out of memory");
  1142.     X    }
  1143.     X    *cp++ = '\0';
  1144.     X    strcpy(cp, val);
  1145.     X    np->am_val = cp + strlen(cp);
  1146.     X}
  1147.     X
  1148.     X/*
  1149.     X * savtok - given the limits of a token string,
  1150.     X *  copy that string (less ATTN bytes) into a dynamically allocated buffer
  1151.     X *  then return the buffer.
  1152.     X */
  1153.     X
  1154.     Xchar *
  1155.     Xsavtok(s, e)
  1156.     Xchar *s;    /* first char of token            */
  1157.     Xchar *e;    /* points beyond the last char of token    */
  1158.     X{
  1159.     X    char *name;    /* the text of the token -- the value to return    */
  1160.     X    char *cp;
  1161.     X    char *malloc();
  1162.     X
  1163.     X    if (!(name = malloc(e - s + 1))) {
  1164.     X        bombf("out of memory");
  1165.     X    }
  1166.     X
  1167.     X    for (cp = name; s < e; ++s) {
  1168.     X        if (*s == ATTN) {
  1169.     X            ++s;
  1170.     X        } else {
  1171.     X            *cp++ = *s;
  1172.     X        }
  1173.     X    }
  1174.     X    *cp = '\0';
  1175.     X
  1176.     X    return(name);
  1177.     X}
  1178. SHAR_EOF
  1179. if test 14405 -ne "`wc -c < 'scpp.c'`"
  1180. then
  1181.     echo shar: error transmitting "'scpp.c'" '(should have been 14405 characters)'
  1182. fi
  1183. fi # end of overwriting check
  1184. echo shar: extracting "'scpp.h'" '(10614 characters)'
  1185. if test -f 'scpp.h'
  1186. then
  1187.     echo shar: will not over-write existing file "'scpp.h'"
  1188. else
  1189. sed 's/^    X//' << \SHAR_EOF > 'scpp.h'
  1190.     X
  1191.     X/*
  1192.     X * scpp.h - common declarations for the selective C preprocessor, scpp.
  1193.     X *
  1194.     X * Copyright (c) 1985 by
  1195.     X * Tektronix, Incorporated Beaverton, Oregon 97077
  1196.     X * All rights reserved.
  1197.     X *
  1198.     X * Permission is hereby granted for personal, non-commercial
  1199.     X * reproduction and use of this program, provided that this
  1200.     X * notice and all copyright notices are included in any copy.
  1201.     X */
  1202.     X
  1203.     X# define TRUE    1
  1204.     X# define FALSE    0
  1205.     X
  1206.     X/*
  1207.     X * sawerror - "some error was processed" If true, scpp exits non-zero.
  1208.     X * Set by the error printout routines, examined when exiting.
  1209.     X */
  1210.     X#ifdef VARS
  1211.     Xint sawerror;
  1212.     X#else
  1213.     Xextern int sawerror;
  1214.     X#endif
  1215.     X
  1216.     X# define BSIZE    512    /*
  1217.     X             * # of bytes per read -- controls how quickly
  1218.     X             * istk[] is consumed.
  1219.     X             */
  1220.     X
  1221.     X/*
  1222.     X * PENDSIZ is a tunable parameter -- it is the largest number of characters
  1223.     X *  which can be waiting to be output.  This number sets a limit on:
  1224.     X *  1) the longest comment;
  1225.     X *  2) the largest invocation of a macro with parameters, i.e. the number
  1226.     X *    of characters between the '(' and the ')'.
  1227.     X *  3) the longest preprocessor control line, e.g. #define....
  1228.     X * PENDSIZ also controls the input stack size, ISTK.
  1229.     X *
  1230.     X * Pend[] is the pending output buffer.
  1231.     X *
  1232.     X * Nxtout points to where within pend[] to put the next token scanned.
  1233.     X * Nxtout is advanced by questr() and quec(),
  1234.     X *  the primitives for putting stuff in pend[],
  1235.     X * and is moved backward by dispose() and outpend(),
  1236.     X *  the primitives for getting stuff out of pend[].
  1237.     X *
  1238.     X * Curtext points to the start of the text within pend[] of
  1239.     X * the current token.  Set by gtok() and gintok().
  1240.     X * For anyone who uses gtok() or gintok() to get
  1241.     X *  a token, the limits of the text of the resultant
  1242.     X *  token are curtext and nxtout. (be aware that the
  1243.     X *  text of anything in pend[] may contain imbedded
  1244.     X *  ATTN bytes.)
  1245.     X */
  1246.     X
  1247.     X# define PENDSIZ 8000
  1248.     X# define PENDHIGH 512    /* highwater mark for flushing pend[]    */
  1249.     X#ifdef VARS
  1250.     Xchar pend[PENDSIZ];
  1251.     Xchar *nxtout;
  1252.     Xchar *curtext;
  1253.     X#else
  1254.     Xextern char pend[];
  1255.     Xextern char *nxtout;
  1256.     Xchar *curtext;
  1257.     X#endif
  1258.     Xextern char *dispose();
  1259.     X#define outpend() (nxtout < &pend[PENDHIGH] ? 0 : writepend())
  1260.     X
  1261.     X/*
  1262.     X * filestk - the stack containing the state of the current file
  1263.     X */
  1264.     X
  1265.     Xstruct afile {
  1266.     X    int    af_fd;        /* the open file's file-descriptor    */
  1267.     X    char    *af_name;    /* the name of the file (dynamic alloc)    */
  1268.     X    int    af_line;    /* the current line in the file        */
  1269.     X    int    af_raw;        /*
  1270.     X                 * "scanning unprocessed data rather than
  1271.     X                 *  pushed-back data".
  1272.     X                 * Used to count input lines.
  1273.     X                 * Also used to prevent
  1274.     X                 *  interpretation of "#if" expressions whose
  1275.     X                 *  truth or falsehood does not depend on
  1276.     X                 *  interpreting macros (e.g. #if '\377' > 0). 
  1277.     X                 */
  1278.     X    int    af_hide;    /*
  1279.     X                 * "do not output anything for this file."
  1280.     X                 * This file is the result of an uninterpreted
  1281.     X                 * "# include".
  1282.     X                 */
  1283.     X};
  1284.     X
  1285.     X#define FILESIZ 11    /* max # of include files + 1 (the original file) */
  1286.     X#ifdef VARS
  1287.     Xstruct afile filestk[FILESIZ];
  1288.     Xstruct afile *curfile;    /* the current file.  Initially = &filestk[-1]    */
  1289.     X#else
  1290.     Xextern struct afile filestk[];
  1291.     Xextern struct afile *curfile;
  1292.     X#endif
  1293.     X
  1294.     X/*
  1295.     X * ISTKSIZ is the size of the input/pushback stack.
  1296.     X *  It contains up to one block of data for each pending file plus
  1297.     X *  one pending token.
  1298.     X * The input stack grows down from istk[ISTKSIZ - 1].
  1299.     X *
  1300.     X * Nxtin points to the next char to read from istk[].
  1301.     X * Characters are popped from the stack by nxtc()
  1302.     X * and are pushed back on the stack by unc() and
  1303.     X * pushmac().
  1304.     X */
  1305.     X
  1306.     X# define ISTKSIZ (FILESIZ * BSIZE + PENDSIZ)
  1307.     X#ifdef VARS
  1308.     Xchar istk[ISTKSIZ];
  1309.     Xchar *nxtin;
  1310.     X#else
  1311.     Xextern char istk[];
  1312.     Xextern char *nxtin;
  1313.     X#endif
  1314.     Xextern char nxtc();
  1315.     Xextern char *pushmac();
  1316.     X#define unc(c) (nxtin-- < &istk[0] ? over() : (*nxtin = c))
  1317.     X
  1318.     X/*
  1319.     X * ATTN appears in the input stack to notify nxtc() of some condition,
  1320.     X *  in the output queue to notify dispose() or outpend() of some condition,
  1321.     X *  or in the value of a macro to notify gintok() of some condition.
  1322.     X * ATTN means that the next byte contains a control code.
  1323.     X * Input control codes are:
  1324.     X *  AT_EPUSH    - end of pushed-back data.  what follows has not been
  1325.     X *         scanned before.
  1326.     X *  AT_EBLK    - end of block.  read another block from the current file.
  1327.     X * Output control codes are:
  1328.     X *  AT_OUTOFF    - disable further output.
  1329.     X *  AT_OUTON    - enable output.
  1330.     X * Macro value control codes are formal parameter numbers and are not defined.
  1331.     X *
  1332.     X * note: to avoid breaking string operations and newline recognition,
  1333.     X *  do not add an ATTN control code which has a value of '\0', '\\', or '\n'.
  1334.     X */
  1335.     X
  1336.     X#define ATTN        '\376'    /* this char must not appear in any file */
  1337.     X#define AT_EPUSH    '\001'
  1338.     X#define AT_EBLK        '\002'
  1339.     X
  1340.     X#define AT_OUTOFF    '\006'
  1341.     X#define AT_OUTON    '\007'
  1342.     X
  1343.     X/*
  1344.     X * Ninterp - number of interpretations.  Incremented each time
  1345.     X *  gintok() interprets a macro.  Since there is no
  1346.     X *  overflow detection, ninterp can be used only to
  1347.     X *  see if some interpretation took place -- not to
  1348.     X *  count the interpretations (e.g. "oldnint != ninterp"
  1349.     X *  works, but "cnt = ninterp - oldnint" may fail).
  1350.     X * Used in conjunction with af_raw to prevent
  1351.     X *  interpretation of  #if's which are always true
  1352.     X *  or false without any macro interpretation (e.g.
  1353.     X *  "#if '\377' > 0").
  1354.     X */
  1355.     X
  1356.     X#ifdef VARS
  1357.     Xint ninterp;
  1358.     X#else
  1359.     Xextern int ninterp;
  1360.     X#endif
  1361.     X
  1362.     X/*
  1363.     X * Falsecnt - number of currently false #if's;
  1364.     X * Hidecnt  - current number of uninterpreted #include's.
  1365.     X * Collectively, these variables are used to determine when
  1366.     X *  to enable or disable output.
  1367.     X */
  1368.     X
  1369.     X#ifdef VARS
  1370.     Xint falsecnt;
  1371.     Xint hidecnt;
  1372.     X#else
  1373.     Xextern int falsecnt;
  1374.     Xextern int hidecnt;
  1375.     X#endif
  1376.     X
  1377.     X/*
  1378.     X * ifstk[] contains flags describing the state of all currently active #if's.
  1379.     X * curif points to the currently active #if within the stack.
  1380.     X * The stack grows upward, starting at ifstk[-1].
  1381.     X */
  1382.     X
  1383.     X#define IF_INIF        '\001'    /* "in the 'if' clause rather than 'else'" */
  1384.     X#define IF_TRUE        '\002'    /* "this if is currently true"           */
  1385.     X#define IF_FALSE    '\004'    /* "this if is currently false"           */
  1386.     X    /* uninterpreted #if statements are neither true nor false.       */
  1387.     X#define IFSIZ    100        /* maximum number of nested #if's       */
  1388.     X#ifdef VARS
  1389.     Xchar ifstk[IFSIZ];
  1390.     Xchar *curif;
  1391.     X#else
  1392.     Xextern char ifstk[];
  1393.     Xextern char *curif;
  1394.     X#endif
  1395.     X
  1396.     X/*
  1397.     X * expparse - "currently parsing a #if expression".
  1398.     X *  Used to prevent interpretation of the macro "defined()" outside
  1399.     X *  #if expressions.
  1400.     X */
  1401.     X
  1402.     X#ifdef VARS
  1403.     Xint expparse;
  1404.     X#else
  1405.     Xextern int expparse;
  1406.     X#endif
  1407.     X
  1408.     X/*
  1409.     X * the next set of definitions are values of parameters to pushfile().
  1410.     X *  PF_NOLOOK    - the filename was given on the command line.  Don't
  1411.     X *         search any directories for it.
  1412.     X *  PF_NODOT    - the include filename was enclosed in '<' and '>'.
  1413.     X *         Do not search the current directory (dot) for the it.
  1414.     X *  PF_DOT    - the include filename was enclosed in double-quotes.
  1415.     X *
  1416.     X *  PF_HIDE    - the file is not to be interpreted (I.e. is an include file).
  1417.     X *         Do not output anything while processing this file.
  1418.     X *  PF_NOHIDE    - the file is to be interpreted.
  1419.     X */
  1420.     X
  1421.     X# define PF_NOLOOK    (-1)
  1422.     X# define PF_NODOT    0
  1423.     X# define PF_DOT        1
  1424.     X
  1425.     X# define PF_HIDE    TRUE
  1426.     X# define PF_NOHIDE    FALSE
  1427.     X
  1428.     X/*
  1429.     X * savcom - "save comments and whitespace"
  1430.     X *  If false, comments and leading and trailing whitespace are removed
  1431.     X *   from interpreted macro definitions.
  1432.     X */
  1433.     X
  1434.     X#ifdef VARS
  1435.     Xint savcom;
  1436.     X#else
  1437.     Xextern int savcom;
  1438.     X#endif
  1439.     X
  1440.     X/*
  1441.     X * catlist - the list of files to process; I.E. the filenames from
  1442.     X *  the command line.  A zero pointer marks the end of the list.
  1443.     X * nxtfile - points to the next element of catlist[] to be processed.
  1444.     X */
  1445.     X
  1446.     X# define CLSIZ        100
  1447.     X#ifdef VARS
  1448.     Xchar *catlist[CLSIZ];
  1449.     Xchar **nxtfile;
  1450.     X#else
  1451.     Xextern char *catlist[];
  1452.     Xextern char **nxtfile;
  1453.     X#endif
  1454.     X
  1455.     X/*
  1456.     X * dirlist - the list of directories to search for an include file.
  1457.     X *  I.E. all the -I directories from the command line + /usr/include.
  1458.     X *  (the search of the current directory of the file is handled separately.)
  1459.     X *  A zero pointer marks the end of the list.
  1460.     X */
  1461.     X
  1462.     X#define DLSIZ        100
  1463.     X#ifdef VARS
  1464.     Xchar *dirlist[DLSIZ];
  1465.     X#else
  1466.     Xextern char *dirlist[];
  1467.     X#endif
  1468.     X
  1469.     X/*
  1470.     X * The symbol table.  All macros are stored in this table.
  1471.     X */
  1472.     X
  1473.     Xstruct amacro {
  1474.     X    char *am_name;    /*
  1475.     X             * the name of this macro (dynamically allocated).
  1476.     X             * An am_name value of 0 means this slot is empty.
  1477.     X             * All macros to be interpreted are allocated slots
  1478.     X             * before any files are scanned.  #define and #undef
  1479.     X             * do not allocate or free symbol-table slots.
  1480.     X             */
  1481.     X    int am_npar;    /* number of parameters.  -1 == no parameters.    */
  1482.     X    char *am_val;    /*
  1483.     X             * the value (replacement text) of the macro.
  1484.     X             * (dynamically allocated.)
  1485.     X             * An am_val value of 0 means that this macro is not
  1486.     X             * currently defined.
  1487.     X             *
  1488.     X             * am_val points to the null-terminator of the
  1489.     X             * replacement text.  The replacement text is to be
  1490.     X             * read backwards from (am_val - 1) until a null-
  1491.     X             * terminator is found at the other end.
  1492.     X             * An ATTN byte followed (well, preceeded if scanning
  1493.     X             *  forward) by a one-byte integer parameter number
  1494.     X             *  is replaced when expanding this macro by the
  1495.     X             *  corresponding actual parameter.
  1496.     X             * To avoid breaking string operations on val strings,
  1497.     X             * parameter numbers begin at 1 rather than 0
  1498.     X             *
  1499.     X             * A visual example may help:
  1500.     X             *   #define goop(name) hello there name people
  1501.     X             *  results in a sym[] slot containing:
  1502.     X             *
  1503.     X             *  am_name:-------------|
  1504.     X             *             V
  1505.     X             *             goop\0
  1506.     X             *  am_npar: 1
  1507.     X             *  am_val:----------------------------|
  1508.     X             *                       V
  1509.     X             *    \0hello there <1><ATTN> people\0
  1510.     X             */
  1511.     X};
  1512.     X
  1513.     X#define SYMSIZ    1001
  1514.     X#ifdef VARS
  1515.     Xstruct amacro sym[SYMSIZ];
  1516.     X#else
  1517.     Xextern struct amacro sym[];
  1518.     X#endif
  1519.     X
  1520.     Xextern struct amacro *findmac();
  1521.     Xextern char *savtok();
  1522.     Xextern int gintok();
  1523.     Xextern int gtok();
  1524.     X
  1525.     X/*
  1526.     X * magicval - This (uninitialized) character is used to
  1527.     X *  recognize special macro's (e.g. "defined()").
  1528.     X * An am_val field of &magicval marks a macro
  1529.     X *  as special -- it cannot be undef'ed or redefined,
  1530.     X *  and macro expansion in gintok() recognizes it.
  1531.     X */
  1532.     X
  1533.     X#ifdef VARS
  1534.     Xchar magicval;
  1535.     X#else
  1536.     Xextern char magicval;
  1537.     X#endif
  1538.     X
  1539.     X#define MAXPARMS 40    /* max number of formal parameters to a macro    */
  1540.     X
  1541.     X/*
  1542.     X * the keyword structure - one of these describes each preprocessor keyword.
  1543.     X * see ctrl.c for the keyword array, key[].
  1544.     X */
  1545.     X
  1546.     Xstruct akeyword {
  1547.     X    char *ak_name;        /* name of this keyword (used to set ak_sym) */
  1548.     X    int (*ak_proc)();    /* procedure to interpret this directive     */
  1549.     X    struct amacro *ak_sym;    /*
  1550.     X                 * pointer to the symbol table slot for this
  1551.     X                 * keyword.  Used to recognise the keyword.
  1552.     X                 * All keywords in this list are effectively
  1553.     X                 * "-M"ed when scpp is invoked.  They are
  1554.     X                 * never defined.
  1555.     X                 *   This field is initialized at runtime.
  1556.     X                 */
  1557.     X};
  1558.     Xextern struct akeyword *findkey();
  1559.     Xextern char *strcpy();
  1560. SHAR_EOF
  1561. if test 10614 -ne "`wc -c < 'scpp.h'`"
  1562. then
  1563.     echo shar: error transmitting "'scpp.h'" '(should have been 10614 characters)'
  1564. fi
  1565. fi # end of overwriting check
  1566. #    End of shell archive
  1567. exit 0
  1568.  
  1569.